﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Egeye.AddIn;

namespace Egeye.AddIn.Core
{
    public class ServiceReference : IServiceReference
    {
        private ServiceRegistration registration = null;
        private IBundle bundle = null;

        public ServiceRegistration Registration
        {
            get
            {
                return registration;
            }
        }

        public ServiceReference(ServiceRegistration registration, IBundle bundle)
        {
            this.registration = registration;
            this.bundle = bundle;
        }

        #region IServiceReference Members

        public object GetProperty(string key)
        {
            if (registration.Properties != null)
            {
                return registration.Properties[key];
            }
            return null;
        }

        public string[] GetPropertyKeys()
        {
            return registration.Properties.Keys.ToArray<string>();
        }

        public Dictionary<string, object> Properties
        {
            get { return registration.Properties; }
        }

        public IBundle GetBundle()
        {
            return bundle;
        }

        public IBundle[] GetUsingBundles()
        {
            return registration.GetUsingBundles();
        }

        public string[] GetClasses()
        {
            return registration.Classes;
        }

        public bool IsAssignableTo(IBundle requester, string className)
        {
            // Always return true if the requester is the same as the provider.
            if (requester == bundle)
            {
                return true;
            }

            // Boolean flag.
            bool allow = true;
            //// Get the package.
            //String pkgName =
            //    Util.getClassPackage(className);
            //// Get package wiring from service requester.
            //IWire requesterWire = Util.getWire(
            //    ((FelixBundle)requester).getInfo().getCurrentModule(), pkgName);
            //// Get package wiring from service provider.
            //IWire providerWire = Util.getWire(
            //    ((FelixBundle)m_bundle).getInfo().getCurrentModule(), pkgName);

            //// There are three situations that may occur here:
            ////   1. The requester does not have a wire for the package.
            ////   2. The provider does not have a wire for the package.
            ////   3. Both have a wire for the package.
            //// For case 1, we do not filter the service reference since we
            //// assume that the bundle is using reflection or that it won't
            //// use that class at all since it does not import it. For
            //// case 2, we have to try to load the class from the class
            //// loader of the service object and then compare the class
            //// loaders to determine if we should filter the service
            //// refernce. In case 3, we simply compare the exporting
            //// modules from the package wiring to determine if we need
            //// to filter the service reference.

            //// Case 1: Always include service reference.
            //if (requesterWire == null)
            //{
            //    // This is an intentional no-op.
            //}
            //// Case 2: Only include service reference if the service
            //// object uses the same class as the requester.
            //else if (providerWire == null)
            //{
            //    // If the provider is not the exporter of the requester's package,
            //    // then try to use the service registration to see if the requester's
            //    // class is accessible.
            //    if (!((FelixBundle)m_bundle).getInfo().hasModule(requesterWire.getExporter()))
            //    {
            //        try
            //        {
            //            // Load the class from the requesting bundle.
            //            Class requestClass =
            //                ((FelixBundle)requester).getInfo().getCurrentModule().getClass(className);
            //            // Get the service registration and ask it to check
            //            // if the service object is assignable to the requesting
            //            // bundle's class.
            //            allow = getServiceRegistration().isClassAccessible(requestClass);
            //        }
            //        catch (Exception ex)
            //        {
            //            // This should not happen, filter to be safe.
            //            allow = false;
            //        }
            //    }
            //    else
            //    {
            //        // O.k. the provider is the exporter of the requester's package, now check
            //        // if the requester is wired to the latest description of the provider, if so
            //        // then allow else don't (the provider has been updated but not refreshed).
            //        allow = ((FelixBundle)m_bundle).getInfo().getCurrentModule() == requesterWire.getExporter();
            //    }
            //}
            //// Case 3: Include service reference if the wires have the
            //// same source module.
            //else
            //{
            //    allow = providerWire.getExporter().equals(requesterWire.getExporter());
            //}

            return allow;
        }

        #endregion
    }
}
